﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using DTC.Popups;
using DTC.Database;

namespace DTC.Assistants
{
    class OptimumAlternative
    {
        public OptimumAlternative()
        {
            dpackList = new List<DTCDrugPack>();
            dboxList = new List<DTCBox>();
        }
        public OptimumAlternative(DTCDrugIssueForm dif)
        {
            InitAtribute(dif);
        }
        private List<DTCBox> dboxList;
        private List<DTCDrugPack> dpackList;
        private double sum;
        private ArrayList alistminimum;
        private ArrayList constantCoefficient;
        public ArrayList ConstantCoefficient
        {
            get { return constantCoefficient; }
            set
            {
                constantCoefficient = value;
                //constantCoefficient.Sort();
                MaxCoefficient = (ArrayList)constantCoefficient.Clone();
            }
        }

        private ArrayList maxCoefficient;
        private ArrayList MaxCoefficient
        {
            get { return maxCoefficient; }
            set
            {
                maxCoefficient = value;
                for (int i = 0; i < value.Count; i++)
                {
                    double d;
                    try
                    {
                        d = sum / (double)value[i];
                        int z = Convert.ToInt32(d);
                        if (z < d) z++;
                        else if (z == 0) z++;
                        maxCoefficient[i] = z;
                    }
                    catch (DivideByZeroException e)
                    {
                        WarningPopup wp = new WarningPopup();
                        wp.Message = e.Message;
                        wp.Title = e.Source;
                        wp.Show();
                    }
                    catch (OverflowException e)
                    {
                        WarningPopup wp = new WarningPopup();
                        wp.Message = e.Message;
                        wp.Title = e.Source;
                        wp.Show();
                    }
                }
            }
        }

        public List<List<Optimum>> GetOptimumBoxes(double sum)
        {
            this.sum = sum;
            ArrayList arr = new ArrayList();
            for (int i = 0; i < dboxList.Count; i++)
            {
                double d = (double)dboxList[i].DrugPack.DrugUnit.Value;
                int v = (int)dboxList[i].DrugPack.NumberOfUnits;
                arr.Insert(i, d*v*(int)dboxList[i].PackCount);
            }
            List<List<Optimum>> allOptList = new List<List<Optimum>>();
            Optimyze(arr);
            for (int j = 0; j < alistminimum.Count; j++)
            {
                List<Optimum> optList = new List<Optimum>();
                for (int i = 0; i < ((Array)alistminimum[j]).Length; i++)
                {
                    if ((int)((Array)alistminimum[j]).GetValue(i) != 0)
                    {
                        Optimum op = new Optimum();
                        op.drugPack = dboxList[i].DrugPack;
                        op.box = dboxList[i];
                        op.boxcount = (int)((Array)alistminimum[j]).GetValue(i);
                        optList.Add(op);

                    }
                }
                allOptList.Add(optList);
            }
            return allOptList;
        }

        public List<List<Optimum>> GetOptimumDrugPack(double sum)
        {
            this.sum = sum;
            ArrayList arr = new ArrayList();
            for (int i = 0; i < dpackList.Count; i++)
                arr.Insert(i,(double)dpackList[i].DTCDrugManufacturer.DTCDrugUnit.Value * (int)dpackList[i].NumberOfUnits);
            List<List<Optimum>> allOptList = new List<List<Optimum>>();
            Optimyze(arr);
            for (int j = 0; j < alistminimum.Count; j++)
            {
                List<Optimum> optList = new List<Optimum>();
                for (int i = 0; i < ((Array)alistminimum[j]).Length; i++)
                {
                    if ((int)((Array)alistminimum[j]).GetValue(i) != 0)
                    {
                        foreach (DTCBox db in dpackList[i].DTCBoxes)
                        {
                            Optimum op = new Optimum();
                            op.drugPack = dpackList[i];
                            op.box = db;
                            op.packcount = (int)((Array)alistminimum[j]).GetValue(i);
                            optList.Add(op);
                        }
                    }
                }
                allOptList.Add(optList);
            }
            return allOptList;
        }

        public List<Optimum> OptimyzeVariants(ArrayList arr, double sum)
        {
            this.sum = sum;
            ConstantCoefficient = arr;
            List<Optimum> optList = new List<Optimum>();
            double min = (double)ConstantCoefficient[ConstantCoefficient.Count - 1];
            double current;
            ArrayList alistminimum = new ArrayList();
            Array schet = maxCoefficient.ToArray();
            Array min_schet = (Array)schet.Clone();
            for (int i = 0; i < schet.Length; i++) schet.SetValue(0, i);
            while (Schetchik(schet))
            {
                current = Fx1xn(schet) - sum;
                if (min > current && current >= 0)
                {
                    min = current;
                    min_schet = (Array)schet.Clone();
                    alistminimum.Clear();
                    alistminimum.Add(min_schet);
                }
                else if (min == current)
                {
                    alistminimum.Add(schet.Clone());
                }
            }
            for (int j = 0; j < alistminimum.Count; j++)
            {
                Optimum op = new Optimum();
                op.Value.AddRange(arr);
                op.Count.AddRange((Array)alistminimum[j]);
                optList.Add(op);
            }
            return optList;
        }

        private void Optimyze(ArrayList arr)
        {
            ConstantCoefficient = arr;
            double min = (double)ConstantCoefficient[ConstantCoefficient.Count - 1];
            double current;
            alistminimum = new ArrayList();
            Array schet = maxCoefficient.ToArray();
            Array min_schet = (Array)schet.Clone();
            for (int i = 0; i < schet.Length; i++) schet.SetValue(0, i);
            while (Schetchik(schet))
            {
                current = Fx1xn(schet) - sum;
                if (min > current && current >= 0)
                {
                    min = current;
                    min_schet = (Array)schet.Clone();
                    alistminimum.Clear();
                    alistminimum.Add(min_schet);
                }
                else if (min == current)
                {
                    alistminimum.Add(schet.Clone());
                }
            }
        }

        private bool Schetchik(Array b)
        {
            bool flag = true;
            int z;
            int i = b.Length - 1;
            int min = EqualToArray(maxCoefficient.ToArray(), b);
            if (min != maxCoefficient.Count)
            {
                for (; i >= min && flag; i--)
                {
                    z = (int)b.GetValue(i) + 1;
                    if (z > (int)maxCoefficient[i])
                    {
                        b.SetValue(0, i);
                        flag = true;
                    }
                    else
                    {
                        b.SetValue(z, i);
                        flag = false;
                    }
                }
                return true;
            }
            else
                return false;
        }

        private double Fx1xn(Array b)
        {
            double sum = 0.0;
            for (int i = 0; i < constantCoefficient.Count || i < b.Length; i++)
            {
                sum += (double)constantCoefficient[i] * (int)b.GetValue(i);
            }
            return sum;
        }

        public int EqualToArray(Array a, Array b)
        {
            int i;
            for (i = 0; (i < a.Length) && ((int)a.GetValue(i) == (int)b.GetValue(i)); i++) ;
            return i;
        }

        private void InitAtribute(DTCDrugIssueForm dif)
        {
            dpackList = new List<DTCDrugPack>();
            dboxList = new List<DTCBox>();
            foreach (DTCDrugUnit du in dif.DTCDrugUnits)
            {
                foreach (DTCDrugManufacturer dm in du.DTCDrugManufacturers)
                    foreach (DTCDrugPack dp in dm.DTCDrugPacks)
                    {
                        dpackList.Add(dp);
                        foreach (DTCBox db in dp.DTCBoxes)
                            dboxList.Add(db);
                    }
            }
        }
    }
}
